package com.asset.modules.login.controller;

import com.asset.modules.system.model.User;
import com.asset.modules.system.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.asset.modules.common.exception.CustomException;
import com.asset.modules.common.exception.CustomUnauthorizedException;
import com.asset.modules.common.model.ResponseBean;
import com.asset.modules.common.servcie.MailService;
import com.asset.modules.common.utils.*;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresGuest;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.HttpStatus;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * UserController
 * @author dolyw.com
 * @date 2018/8/29 15:45
 */
@RestController
@RequestMapping("/userLogin")
@PropertySource("classpath:config.properties")
@EnableSwagger2
@Api(tags = "用户登陆")
public class SysUserController {

    /**
     * RefreshToken过期时间
     */
    @Value("${refreshTokenExpireTime}")
    private String refreshTokenExpireTime;

    @Autowired
    private UserService us;

    /**
     * 验证码过期时间
     */
    @Value("${verifyCodeExpireTime}")
    private String verifyCodeExpireTime;

    @Value("${spring.mail.username}")
    private String from;

    @Autowired
    private UserUtil userUtil;

    @Autowired
    private UserService userService;

    @Autowired
    private DefaultKaptcha producer;

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private MailService mailService;

    /**
     * 登录授权
     * @param username
     * @Param password
     * @Param code
     * @return com.wang.model.common.ResponseBean
     * @author dolyw.com
     * @date 2018/8/30 16:21
     */
    @GetMapping("/login")
    @ApiOperation(value = "登陆", notes = "用户名，密码必填")
    public ResponseBean login(@RequestParam String username,
                              @RequestParam String password,
                              HttpServletResponse httpServletResponse,
                              HttpServletRequest request) {
        // 查询数据库中的帐号信息

        User user = userService.getUser("user_name", username);

        if (user == null) {
            return new ResponseBean(HttpStatus.INTERNAL_SERVER_ERROR.value(), Constant.NO_USER, null);
        }
        // 密码进行AES解密
        String key = AesCipherUtil.deCrypto(user.getPassword());
        // 因为密码加密是以帐号+密码的形式进行加密的，所以解密后的对比是帐号+密码
        if (key.equals(username + password)) {
            //验证验证码是否正确
            //取得请求头内的codeToken
//            String codeToken = request.getHeader("CodeToken");
//            if(StringUtil.isNotBlank(codeToken)&&StringUtil.isNotBlank(code)){
//                //根据CodeToken从redis取得CreateText
//                String createText = JedisUtil.getObject(codeToken)+"";
//                //验证码文本不符
//                if(!code.equals(createText)){
//                    throw new CustomUnauthorizedException("验证码错误.");
//                }
//            }
//            else{
//                throw new CustomUnauthorizedException("验证码错误.");
//            }
            // 清除可能存在的Shiro权限信息缓存
            if (JedisUtil.exists(Constant.PREFIX_SHIRO_CACHE + user.getUserName())) {
                JedisUtil.delKey(Constant.PREFIX_SHIRO_CACHE + user.getUserName());
            }
            // 设置RefreshToken，时间戳为当前时间戳，直接设置即可(不用先删后设，会覆盖已有的RefreshToken)
            String currentTimeMillis = String.valueOf(System.currentTimeMillis());
            JedisUtil.setObject(Constant.PREFIX_SHIRO_REFRESH_TOKEN + user.getUserName(), currentTimeMillis, Integer.parseInt(refreshTokenExpireTime));
            // 从Header中Authorization返回AccessToken，时间戳为当前时间戳
            String token = JwtUtil.sign(user.getUserName(), currentTimeMillis);
            httpServletResponse.setHeader("Authorization", token);
            httpServletResponse.setHeader("Access-Control-Expose-Headers", "Authorization");
            return new ResponseBean(HttpStatus.OK.value(), "登录成功", user);
        } else {
            return new ResponseBean(HttpStatus.INTERNAL_SERVER_ERROR.value(), "密码不正确，请重新输入密码！", null);
        }
    }

    /**
     * 登陆授权
     * @param mobile
     * @param httpServletResponse
     * @param request
     * @return
     */
    @GetMapping("/login/mobile")
    @ApiOperation(value = "手机登陆", notes = "手机号码")
    public ResponseBean login(@RequestParam String mobile,
                              HttpServletResponse httpServletResponse, HttpServletRequest request){
        // 查询数据库中的帐号信息
        User user = userService.getUser("mobile", mobile);
        if (user == null) {
            return new ResponseBean(HttpStatus.FORBIDDEN.value(), "该手机号码用户未注册!", null);
        }

        if (JedisUtil.exists(Constant.PREFIX_SHIRO_CACHE + user.getUserName())) {
            JedisUtil.delKey(Constant.PREFIX_SHIRO_CACHE + user.getUserName());
        }
        // 设置RefreshToken，时间戳为当前时间戳，直接设置即可(不用先删后设，会覆盖已有的RefreshToken)
        String currentTimeMillis = String.valueOf(System.currentTimeMillis());
        JedisUtil.setObject(Constant.PREFIX_SHIRO_REFRESH_TOKEN + user.getUserName(), currentTimeMillis, Integer.parseInt(refreshTokenExpireTime));
        // 从Header中Authorization返回AccessToken，时间戳为当前时间戳
        String token = JwtUtil.sign(user.getUserName(), currentTimeMillis);
        httpServletResponse.setHeader("Authorization", token);
        httpServletResponse.setHeader("Access-Control-Expose-Headers", "Authorization");
        return new ResponseBean(HttpStatus.OK.value(), "登录成功！", user);

    }




    @RequestMapping(value = "/code", method = RequestMethod.GET)
    @ApiOperation(value = "验证码接口")
    public void fetchVerifyCode(HttpServletResponse httpServletResponse, HttpServletRequest request){
        byte[] verByte = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        //生产验证码字符串并保存在redis中
        String createText = producer.createText();
        //使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
        BufferedImage challenge = producer.createImage(createText);
        try {
            //生成验证码对应的token  以token为key  验证码为value存在redis中
            String codeToken = UUIDUtil.getUUID();
            JedisUtil.setObject(codeToken, createText, Integer.parseInt(verifyCodeExpireTime));
            ImageIO.write(challenge,"jpg",jpegOutputStream);
            //定义response输出类型为image/jpeg类型，使用response输出流输出图片的byte数组
            verByte = jpegOutputStream.toByteArray();
            httpServletResponse.setHeader("Cache-Control", "no-store");
            httpServletResponse.setHeader("Pragma", "no-cache");
            httpServletResponse.setDateHeader("Expires", 0);
            httpServletResponse.setContentType("image/jpeg");
            httpServletResponse.setHeader("CodeToken", codeToken);
            httpServletResponse.setHeader("Access-Control-Expose-Headers", "CodeToken");
            ServletOutputStream responseOutputStream = httpServletResponse.getOutputStream();
            responseOutputStream.write(verByte);
            responseOutputStream.flush();
            responseOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    /**
     * 测试登录
     * @param
     * @return com.wang.model.common.ResponseBean
     * @author dolyw.com
     * @date 2018/8/30 16:18
     */
    @GetMapping("/article")
    @ApiOperation(value = "测试登陆接口", notes = "无需传参")
    public ResponseBean article() {
        Subject subject = SecurityUtils.getSubject();
        // 登录了返回true
        if (subject.isAuthenticated()) {
            return new ResponseBean(HttpStatus.OK.value(), "您已经登录了(You are already logged in)", null);
        } else {
            return new ResponseBean(HttpStatus.OK.value(), "你是游客(You are guest)", null);
        }
    }

    /**
     * 测试登录注解(@RequiresAuthentication和subject.isAuthenticated()返回true一个性质)
     * @param
     * @return com.wang.model.common.ResponseBean
     * @author dolyw.com
     * @date 2018/8/30 16:18
     */
    @GetMapping("/article2")
    @RequiresAuthentication
    @ApiOperation(value = "测试登陆注解接口")
    public ResponseBean requireAuth() {
        return new ResponseBean(HttpStatus.OK.value(), "您已经登录了(You are already logged in)", null);
    }

    /**
     * 获取当前登录用户信息
     * @param
     * @return com.wang.model.common.ResponseBean
     * @author dolyw.com
     * @date 2019/3/15 11:51
     */
    @GetMapping("/info")
    @RequiresAuthentication
    @ApiOperation(value = "用户信息")
    public ResponseBean info() {
        // 获取当前登录用户
        User user = userUtil.getUser();
        // 获取当前登录用户Id
        Long id = userUtil.getUserId();
        // 获取当前登录用户Token
        String token = userUtil.getToken();
        // 获取当前登录用户Account
        String account = userUtil.getAccount();
        user.setPassword("******");
        return new ResponseBean(HttpStatus.OK.value(), "您已经登录了(You are already logged in)", user);
    }

    /**
     * 普通用户注册
     * */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @ApiOperation("用户信息注册接口")
    @RequestMapping(value="/register",method= RequestMethod.POST)
    public ResponseBean register(@RequestBody User user){
        //判断必要信息是否已填
        if(user!=null
                && (!StringUtils.isEmpty(user.getUserName()))
                && (!StringUtils.isEmpty(user.getPassword()))
        ){
            User _user = new User();
//            SysUserDetail sysUserDetail = new SysUserDetail();
            //判断用户名是否已存在
            if(userService.checkExistByUserName(user.getUserName())){
                throw new CustomException("该用户账户已被使用！");
            }
            //判断昵称是否已存在
            if(userService.checkExistByNickName(user.getUserNicky())){
                throw new CustomException("该用户昵称已被使用！");
            }
            //判断邮箱是否已存在
//            if(sysUserDetailService.checkExistByEmail(userVo.getEmail())){
//                throw new CustomException("该邮箱已被使用！");
//            }
            //用户账户
            _user.setUserName(user.getUserName());
            //用户密码(进行AES加密)
            _user.setPassword(AesCipherUtil.enCrypto(user.getUserName()+user.getPassword()));
            _user.setCompanyCode(user.getCompanyCode());
            _user.setCompanyName(user.getCompanyName());
            _user.setPermission(user.getPermission());
            _user.setRoleId(user.getRoleId());
            _user.setRoleName(user.getRoleName());
            _user.setUserNicky(user.getUserNicky());
            String verifyCode = UUIDUtil.getUUID(10);
            //储存验证码(30分钟有效时限)
            JedisUtil.setObject(user.getUserName(),verifyCode,30*60);
            //生成验证链接
            String verifyUrl = mailService.generateVerifyUrl(user.getUserName(),verifyCode);
//            //发送邮件链接
//            SimpleMailMessage message = new SimpleMailMessage();
//            message.setFrom(from);
////          message.setTo(sysUserDetail.getEmail());
//            message.setSubject("asset帐户 - 电子邮件确认");
//            String verifyText = mailService.generateVerifyText();
//            verifyText = String.format(verifyText,verifyUrl);
//            message.setText(verifyText);
//            //发送邮件
//            javaMailSender.send(message);
            userService.save(_user);
//            sysUser.setPassword(null);
            return new ResponseBean(HttpStatus.OK.value(),"用户注册成功!",_user);
        }
        else{
            throw new CustomException("用户注册信息不完整");
        }
    }

    /**
     *  密码邮件找回(测试专用)
     * */
    @RequiresGuest
    @ApiOperation("密码邮件找回接口")
    @RequestMapping(value="/email",method= RequestMethod.GET)
    public ResponseBean getPassword(@RequestParam String username,
                                 @RequestParam String email){
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(email);
        message.setSubject("asset用户验证码");
        User u = us.getUser("user_name", username);
        String key = AesCipherUtil.deCrypto(u.getPassword());
        String password = key.substring(username.length());
        message.setText("敬爱的用户:"+u.getUserNicky()+" 您的密码为:"+password);
        javaMailSender.send(message);
        return new ResponseBean(HttpStatus.OK.value(),"验证码邮件已发送",null);
    }


}